package sliceutil

import (
	"errors"
	"fmt"
	"log"
	"reflect"
	"regexp"
	"strconv"
	"strings"

	"gitee.com/haodreams/libs/easy"
)

//获取bool值
func getBoolValue(value reflect.Value) (b bool, err error) {
	switch value.Kind() {
	case reflect.String:
		b, err = strconv.ParseBool(value.String())
	case reflect.Bool:
		b = value.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		b = value.Int() == 1
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		b = value.Uint() == 1
	case reflect.Float32, reflect.Float64:
		b = value.Float() == 1
	default:
		err = errors.New("param error type")
		return
	}
	return
}

func getIntValue(value reflect.Value) (b int64, err error) {
	switch value.Kind() {
	case reflect.String:
		var ival int
		ival, err = strconv.Atoi(value.String())
		b = int64(ival)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		b = value.Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		b = int64(value.Uint())
	case reflect.Float32, reflect.Float64:
		b = int64(value.Float())
	default:
		err = errors.New("param error type")
		return
	}
	return
}

func getUintValue(value reflect.Value) (b uint64, err error) {
	switch value.Kind() {
	case reflect.String:
		b, err = strconv.ParseUint(value.String(), 10, 64)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		b = uint64(value.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		b = value.Uint()
	case reflect.Float32, reflect.Float64:
		b = uint64(value.Float())
	default:
		err = errors.New("param error type")
		return
	}
	return
}

func getFloatValue(value reflect.Value) (b float64, err error) {
	switch value.Kind() {
	case reflect.String:
		b, err = strconv.ParseFloat(value.String(), 64)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		b = float64(value.Int())
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		b = float64(value.Uint())
	case reflect.Float32, reflect.Float64:
		b = float64(value.Float())
	default:
		err = errors.New("param error type")
		return
	}
	return
}

func getStringValue(value reflect.Value) (b string) {
	switch value.Kind() {
	case reflect.String:
		b = value.String()
	default:
		return fmt.Sprint(value.Interface())
	}
	return
}

//WhereMap 查询多个条件过滤
//interface 如果有过滤条件将生成新的 数组结构体
//如果没有过滤条件 返回原始的数组结构体
func WhereMap(mp map[string]string, slices interface{}, isReg ...bool) interface{} {
	keys := make([]string, 0)
	values := make([]string, 0)
	for key, value := range mp {
		if strings.HasPrefix(key, "search_") {
			value = strings.TrimSpace(value)
			if value != "" {
				key = strings.TrimPrefix(key, "search_")
				if key == "" {
					continue
				}

				key = strings.ToLower(key)

				keys = append(keys, key)
				values = append(values, value)
			}
		} else if strings.HasPrefix(key, "where_") {
			value = strings.TrimSpace(value)
			if value != "" {
				key = strings.TrimPrefix(key, "where_")
				if key == "" {
					continue
				}
				key = strings.ToLower(key)

				keys = append(keys, key)
				values = append(values, value)
			}
		}
	}

	if len(keys) == 0 {
		return slices
	}

	//复制一份属据
	list := reflect.ValueOf(slices)
	listType := list.Type()
	if listType.Kind() != reflect.Slice {
		log.Println(errors.New("Not slice " + fmt.Sprint(listType.Kind())))
		return slices
	}
	num := list.Len()
	if num == 0 {
		return slices
	}
	valueType := list.Index(0).Type()
	if valueType.Kind() == reflect.Invalid {
		log.Println("Value invalid")
		return slices
	}

	newList := reflect.New(list.Type()).Elem()
	newList.Set(reflect.MakeSlice(list.Type(), list.Len(), list.Cap()))
	for i := 0; i < num; i++ {
		newList.Index(i).Set(list.Index(i))
	}

	interf := newList.Interface()
	for i := range keys {
		idx, err := Where(interf, keys[i], values[i], isReg...)
		if err != nil {
			log.Println(err)
		} else {
			newList.SetLen(idx)
			interf = newList.Interface()
		}
	}
	return newList.Interface()
}

//Where 过滤数据
//slice struct数组
//name struct
//value
//isReg 字符串值时，是否使用正则
func Where(slice interface{}, name string, value interface{}, isReg ...bool) (idx int, err error) {
	if name == "" {
		return
	}

	list := reflect.Indirect(reflect.ValueOf(slice))
	listType := list.Type()
	if listType.Kind() != reflect.Slice {
		return 0, errors.New("Not slice " + fmt.Sprint(listType.Kind()))
	}
	num := list.Len()
	if num == 0 {
		return
	}
	//idx := 0
	valueKind := reflect.ValueOf(value)
	if valueKind.Kind() == reflect.Invalid {
		err = errors.New("value invalid")
		return
	}

	keyMap := map[string][]int{}
	easy.MapNameID("", keyMap, nil, reflect.Indirect(list.Index(0)).Type(), true)
	ids, ok := keyMap[name]
	if !(ok && len(ids) > 0) {
		err = errors.New("value's name invalid")
		return
	}

	structValue, err := reflect.Indirect(list.Index(0)).FieldByIndexErr(ids)
	if err != nil {
		return
	}

	structValue = reflect.Indirect(structValue)

	if structValue.Kind() == reflect.String {
		where := getStringValue(valueKind)
		if len(isReg) > 0 && isReg[0] {
			reg, err := regexp.Compile(where)
			if err != nil {
				return 0, err
			}
			for i := 0; i < num; i++ {
				structValue := reflect.Indirect(reflect.Indirect(list.Index(i)).FieldByIndex(ids))
				if reg.MatchString(structValue.String()) {
					list.Index(idx).Set(list.Index(i))
					idx++
				}
			}
		} else {
			for i := 0; i < num; i++ {
				structValue := reflect.Indirect(reflect.Indirect(list.Index(i)).FieldByIndex(ids))
				if strings.Contains(structValue.String(), where) {
					list.Index(idx).Set(list.Index(i))
					idx++
				}
			}
		}
	} else {
		switch structValue.Kind() {
		case reflect.Bool:
			paramValue, err := getBoolValue(valueKind)
			if err != nil {
				return 0, err
			}
			for i := 0; i < num; i++ {
				structValue := reflect.Indirect(reflect.Indirect(list.Index(i)).FieldByIndex(ids))
				if structValue.Bool() == paramValue {
					list.Index(idx).Set(list.Index(i))
					idx++
				}
			}
		// Ints
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			paramValue, err := getIntValue(valueKind)
			if err != nil {
				return 0, err
			}
			for i := 0; i < num; i++ {
				structValue := reflect.Indirect(reflect.Indirect(list.Index(i)).FieldByIndex(ids))
				if structValue.Int() == paramValue {
					list.Index(idx).Set(list.Index(i))
					idx++
				}
			}
		// Uints
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			paramValue, err := getUintValue(valueKind)
			if err != nil {
				return 0, err
			}
			for i := 0; i < num; i++ {
				structValue := reflect.Indirect(reflect.Indirect(list.Index(i)).FieldByIndex(ids))
				if structValue.Uint() == paramValue {
					list.Index(idx).Set(list.Index(i))
					idx++
				}
			}
		// Floats
		case reflect.Float32, reflect.Float64:
			paramValue, err := getFloatValue(valueKind)
			if err != nil {
				return 0, err
			}
			for i := 0; i < num; i++ {
				structValue := reflect.Indirect(reflect.Indirect(list.Index(i)).FieldByIndex(ids))
				if structValue.Float() == paramValue {
					list.Index(idx).Set(list.Index(i))
					idx++
				}
			}
		}
	}
	log.Println(idx)
	//list.SetLen(idx)
	return
}
